<?php

namespace App\Http\Controllers;

use App\Models\Campus;
use App\Models\Containers;
use App\Models\Packages;
use App\Models\Staffs;
use App\Models\Users;
use GuzzleHttp\Exception\ServerException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Mockery\Exception;

class PackagesController extends Controller
{

    public function showByUser($tracking_number){
        $package = Packages::where('number', $tracking_number)->with('packages_info')->first();
        if ($package == null){
            return $this->returnNotFoundError();
        }
        $from = Campus::where('id' , $package->from_campus_id)->first();
        $to = Campus::where('id' , $package->to_campus_id)->first();
        $json = [
            'id' => $package->id,
            'tracking_number' => $package->number,
            'from_campus' => $from->name,
            'from_address' => $package->sender_address,
            'to_campus' => $to->name,
            'to_address' => $package->recipient_address,
            'progress' => []
        ];
        foreach ($package->toArray()['packages_info'] as $key => $value) {
            $info = [
                'state' => $value['state'],
                'datetime' => $value['created_at'],
                'returning' => $value['returning'],
            ];
            if ($value['state'] == 'In transit'){
                $info['campus'] = $from->name;
            }
            $json['progress'][] =$info;
        }
        return $this->returnJson($json);
    }

    public function sendPackage(Request $request){
        $data = request()->only(['from_campus_id' , 'from_address' , 'to_campus_id' , 'to_address' , 'recipient_name' , 'recipient_phone_number']);
        $validation = Validator::make($data, [
            'from_campus_id' => 'required | integer',
            'from_address' => 'required | string',
            'to_campus_id' => 'required | integer',
            'to_address' => 'required | string',
            'recipient_name' => 'required',
            'recipient_phone_number' => 'required | min:8 | max:12'
        ]);
        if($validation->fails()){
            return $this->returnValidationError("data can not be processed");
        }
        if ($data['from_campus_id'] == $data['to_campus_id']){
            return $this->returnValidationError("cannot send the package to the same campus");
        }
        $from_campus = Campus::where("id" , $data['from_campus_id'])->first();
        $to_campus = Campus::where("id" , $data['to_campus_id'])->first();
        if ($from_campus == null || $to_campus == null) {
            return $this->returnValidationError("campus does not exist");
        }
        $couriers = Staffs::where("campus_id" , $data['from_campus_id'])->get();
        if ($couriers == null){
            return $this->returnAlreadyError("no available couriers in the campus");
        }

        $couriers = $couriers[rand(0, count($couriers) - 1)];

        $user = Users::where("id" , $request->object_id)->first();

        $package = Packages::create([
            "number" => "CE" . $from_campus->code . $to_campus->code . date("Ymd" , time()) . rand(100 , 999),
            "user_id" => $request->object_id,
            "sender_name" => $user->first_name . " " . $user->last_name,
            "sender_phone" => $user->phone,
            "sender_address" => $data["from_address"],
            "delivery_id" => $couriers->id,
            "from_campus_id" => $from_campus->id,
            "to_campus_id" => $to_campus->id,
            "recipient_name" => $data['recipient_name'],
            "recipient_phone" => $data['recipient_phone_number'],
            "recipient_address" => $data['to_address'],
        ]);

        return $this->returnJson([
            "id" => $package->id,
            "courier_name" => $user->first_name . " " . $user->last_name,
            "courier_phone_number" => $user->phone,
        ]);
    }

    public function getUserPackages(Request $request){
        $packages = Packages::where("user_id" , $request->object_id)->get();
        $json = [];
        foreach ($packages as $package) {
            $recipient = Staffs::where("id" , $package->delivery_id)->first();
            $json[] = [
                "id" => $package->id,
                "tracking_number" => $package->number,
                "from_campus" => Campus::where("id" , $package->from_campus_id)->first()->name,
                "from_address" => $package->sender_address,
                "to_campus" => Campus::where("id" , $package->to_campus_id)->first()->name,
                "to_address" => $package->recipient_address,
                "returning" => $package->returning,
                "send_time" => $package->created_at,
                "recipient" => [
                    "name" => $recipient->first_name . " " . $recipient->last_name,
                    "phone_number" => $recipient->phone,
                ]
            ];
        }
        return $this->returnJson($json);
    }

    public function returnPackage($package_id , Request $request){
        if($package_id == null){
            return $this->returnNotFoundError();
        }
        $package = Packages::where("number" , $package_id)->first();
        if ($package == null){
            return $this->returnNotFoundError();
        }
        if ($package->user_id !=  $request->object_id){
            return $this->returnPositionError("you cannot return other client's packages");
        }
        $state = null;
        switch ($package->state){
            case "Pending pickup":
                $state = 6;
                break;
            case "Picked up":
                $state = 5;
                break;
            case "Pending delivery":
                $state = 2;
                break;
            case "Delivered":
                $state = 1;
                break;
            default:
        }
        if($state != null){
            $package->state = $state;
            $package->save();
        }
        $package = Packages::where("number" , $package_id)->first();
        return $this->returnJson([
            "id" => $package->id,
            "status" => $package->state,
        ]);
    }

    public function getPendingPickupPackage(Request $request){
        $staff = Staffs::where("id" , $request->object_id)->first();
        $packages = Packages::where("state" , "0")->where("delivery_id" , $request->object_id)->with(['from_campus' , 'to_campus' , 'sender'])->get();
        $json = [];
        foreach ($packages as $package){
            $json[] = [
                'id' => $package->id,
                'tracking_number' => $package->number,
                'from_campus' => $package->from_campus->name,
                'from_address' => $package->sender_address,
                'to_campus' => $package->to_campus->name,
                'to_address' => $package->recipient_address,
                'sender' => [
                    'id' => $package->sender->id,
                    'firstname' => $package->sender->first_name,
                    'lastname' => $package->sender->last_name,
                    'phone_number' => $package->sender->phone,
                ],
                "recipient" => [
                    "name" => $staff->first_name . " " . $staff->last_name,
                    "phone_number" => $staff->phone,
                ]
            ];
        }
        return $this->returnJson($json);
    }

    public function pickedUp(Request $request){

        $packages = request()->only('package_id_list');
        $validator = Validator::make($packages , [
            'package_id_list' => 'required | array'
        ]);
        if ($validator->fails()){
            return $this->returnValidationError("data can not be processed");
        }
        $packages = ['package_id_list' => [1 , 2 , -1]];
        $staff = Staffs::where("id" , $request->object_id)->first();
        $packages = Packages::where("delivery_id" , $request->object_id)
            ->where("state" , "0")
            ->whereIn("id" , $packages['package_id_list'])
            ->get();


        if ($staff->package_number + count($packages) > 5){
            return $this->returnAlreadyError("over the courier's remaining capacity" , [
                'remaining_capacity' => 5 - $staff->package_number,
            ]);
        }
        $ids = [];
        try {
            DB::beginTransaction();
            foreach ($packages as $package){
                $package->state = "1";
                $package->save();
                $ids[] = $package->id;
            }
            $staff->package_number = $staff->package_number + count($packages);
            $staff->total_picked = $staff->total_picked + count($packages);
            DB::commit();
        }catch (Exception $e){
            DB::rollback();
            throw new ServerException("server error");
        }
        return $this->returnJson([
            'package_id_list' => $ids
        ]);
    }

    public function getCampusPendingPackage(Request $request){
        $staff = Staffs::where("id" , $request->object_id)->first();
        $packages = Packages::where("to_campus_id" , $staff->campus_id)
            ->where("state" , "4")
            ->with(['from_campus' , 'to_campus' , 'sender' , 'delivery'])
            ->get();
        $json = [];
        foreach ($packages as $package){
            $json[] = [
                'id' => $package->id,
                'tracking_number' => $package->number,
                'from_campus' => $package->from_campus->name,
                'from_address' => $package->sender_address,
                'to_campus' => $package->to_campus->name,
                'to_address' => $package->recipient_address,
                'sender' => [
                    'id' => $package->sender->id,
                    'firstname' => $package->sender->first_name,
                    'lastname' => $package->sender->last_name,
                    'phone_number' => $package->sender->phone,
                ],
                "recipient" => [
                    "name" => $package->delivery->first_name . " " . $package->delivery->last_name,
                    "phone_number" => $package->delivery->phone,
                ]
            ];
        }
        return $this->returnJson($json);
    }

    public function delivery(Request $request){
        $packages = request()->only('package_id_list');
        $validator = Validator::make($packages , [
            'package_id_list' => 'required | array'
        ]);
        if ($validator->fails()){
            return $this->returnValidationError("data can not be processed");
        }
        $staff = Staffs::where("id" , $request->object_id)->first();
        $packages = Packages::where("delivery_id" , $request->object_id)
            ->where("state" , "4")
            ->whereIn("id" , $packages['package_id_list'])
            ->whereNull('containers_id')
            ->get();

        if ($staff->package_number + count($packages) > 5){
            return $this->returnAlreadyError("over the courier's remaining capacity" , [
                'remaining_capacity' => 5 - $staff->package_number,
            ]);
        }
        $ids = [];
        try {
            DB::beginTransaction();
            foreach ($packages as $package){
                $package->state = "5";
                $package->save();
                $ids[] = $package->id;
            }
            $staff->package_number = $staff->package_number + count($packages);
            $staff->total_delivered = $staff->total_delivered + count($packages);
            DB::commit();
        }catch (Exception $e){
            DB::rollback();
        }
        return $this->returnJson([
            'package_id_list' => $ids
        ]);
    }

    public function packing(){
        $packages = request()->only('package_id_list');
        $validator = Validator::make($packages , [
            'package_id_list' => 'required | array'
        ]);
        if ($validator->fails()){
            return $this->returnValidationError("data can not be processed");
        }
        $packages = Packages::where("state" , "4")
            ->whereIn("id" , $packages['package_id_list'])
            ->whereNull('containers_id')
            ->get();
        $packages_id_list = [];
        $container_id_list = [];
        foreach ($packages as $package){
            $from_campus_id = $package->from_campus_id;
            $to_campus_id = $package->to_campus_id;
            $container = Containers::where("from_campus_id" , $from_campus_id)
                ->where("to_campus_id" , $to_campus_id)
                ->whereNull('staffs_id')
                ->where("quantity"  , "<" , 5)
                ->first();
            if ($container == null){
                try {
                    DB::beginTransaction();
                    $container = Containers::create([
                        'from_campus_id' => $from_campus_id,
                        'to_campus_id' => $to_campus_id,
                        'quantity' => 1,
                    ]);
                    $package->containers_id = $container->id;
                    $package->save();
                    DB::commit();
                }catch (Exception $e){
                    DB::rollback();
                }
            }else{
                try {
                    DB::beginTransaction();
                    $container->quantity = $container->quantity + 1;
                    $container->save();
                    $package->containers_id = $container->id;
                    $package->save();
                    DB::commit();
                }catch (Exception $e){
                    DB::rollBack();
                }
            }
            array_push($packages_id_list, $package->id);
            if (in_array($container->id, $container_id_list) == false) {
                array_push($container_id_list, $container->id);
            }
        }

        return $this->returnJson([
            'container_id_list' => $container_id_list,
            'package_id_list' => $packages_id_list
        ]);
    }

    public function getDeliveryPackage(Request $request){

        $packages = Packages::where("state" , "5")
            ->where("dispatch_id" , $request->object_id)
            ->with(['from_campus' , 'to_campus' , 'sender' , 'delivery'])
            ->get();

        $json = [];
        foreach ($packages as $package){
            $json[] = [
                'id' => $package->id,
                'tracking_number' => $package->number,
                'from_campus' => $package->from_campus->name,
                'from_address' => $package->sender_address,
                'to_campus' => $package->to_campus->name,
                'to_address' => $package->recipient_address,
                'sender' => [
                    'id' => $package->sender->id,
                    'firstname' => $package->sender->first_name,
                    'lastname' => $package->sender->last_name,
                    'phone_number' => $package->sender->phone,
                ],
                "recipient" => [
                    'name' => $package->delivery->first_name . " " . $package->delivery->last_name,
                    'phone_number' => $package->delivery->phone,
                ]
            ];
        }
        return $this->returnJson($json);
    }

    public function getByContainer($container_id){
        $packages = Packages::where("containers_id" , $container_id)->with('sender')->get();
        $json = [];
        foreach ($packages as $package){
            $json[] = [
                'id' => $package->id,
                'firstname' => $package->sender->first_name,
                'lastname' => $package->sender->last_name,
                'phone_number' => $package->sender->phone,
            ];
        }
        return $this->returnJson($json);
    }
}
